const express = require('express')
// 日志工具
const morgan = require('morgan');

// 创建 express 的服务器实例
const app = express()
const joi = require('joi')
// 解析token
const expressJWT = require('express-jwt')
// 配置文件
const config = require('./src/utils/config')
// 工具包
const {isEqual,guid} = require('./src/utils/index')
// 数据库操作方法
const {sqlOne} = require('./src/db/common')
// === 普通的控制台打印 ===
// 自定义日志格式
// morgan.format('joke', '[joke] :method :url :status');
// 选择指定格式
// app.use(morgan('joke'));


// write your code here...
app.get("/", (req, res) => {
  res.send("123")
})

var bodyParser = require("body-parser")
app.use(bodyParser.json()) // 解析json
app.use(bodyParser.urlencoded({ extended: false })) // 是否格式化表单

const commemorateRoter = require("./src/rourer/commemorateRouter");
// 导入 greatperson 路由
const greatpersonRoter = require("./src/rourer/greatpersonRouter");
// 导入 property 路由
const propertyRouter = require("./src/rourer/propertyRouter");
// 导入user跟由
const userRouter = require("./src/rourer/userRouter");
// 注册一个全局 处理失败中间件 
app.use((req, res, next) => {
  // const role = req.auth.role;
  // console.log(role);
  // console.log(req.method);

  // 生成时间戳
  req.nowTime = new Date();
  // 所有路由都会先经过这个中间件  都会产生一个 res.cc 的函数 可以直接在后面进行调用
  res.onError = function (err = "服务出错，请稍后重试", status = 400) {
    res.send({
      status,
      // 判断err是字符串还是错误对象
      message: err instanceof Error ? err.message : err
    })
  }
  res.onSuccess = function (data, message = "成功", status = 200) {
    res.send({
      status,
      data,
      message
    })
  }
  next()
})

// token验证中间件
app.use(expressJWT.expressjwt({ secret: config.jwtSecretKey, algorithms: ['HS256'] }).unless({ path: [/^\/public\//, /^\/user\//] }))

// 挂载权限验证中间件
app.use((req, res, next) => {
  // req.token = req.headers.authorization;
  // console.log(req.token);
  // 判断token解析的数据中role的值
  console.log(req.user);
  if(!req.auth){
    return next()
  }
  const role = req.auth.role;
  if (role === 0 ) {
    if (isEqual(req.method, "GET")){
      return next()
    }else{
      return res.onError("权限不足，无法操作")
    }
  }
  return next()
  // 判断请求类型 
  // if(role===0&&req.method)
})

// === 实现数据库日志操作 ===
// 自定义 token
morgan.token('user', (req, res) => {
  // 在这里定义你的自定义逻辑
  return req.auth?req.auth.username:null;
});
morgan.token('body', (req, res) => {
  // 在这里定义你的自定义逻辑
  return JSON.stringify(req.body || null);
});
morgan.format('joke', ':method :url :status :response-time :res[content-length] :user :body');
const dbStream = {
  write: function (line) {
    console.log(line);
    const arr = ['method', 'url', 'status','timeconsuming','reslength','user','body']
    line = line.split(' ')
    // console.log(line);
    let obj = line.reduce((acc, curr, index) => {
      acc[arr[index]] = curr;
      return acc;
    }, { id: guid() ,time:new Date()});
    // 存入数据库
   sqlOne('insert into logs set ?', obj).then(res=>{
    // console.log(res);
    if(res.affectedRows===1){
      console.log('日志插入成功');
    }
  })
    // console.log(obj);
  }
}
app.use(morgan('joke', { stream: dbStream }));



// 挂载路由
app.use('/public', commemorateRoter)
app.use('/user', userRouter)
app.use('/greatperson', greatpersonRoter)
app.use('/property', propertyRouter)



// 错误中间件
app.use(function (err, req, res, next) {
  // console.log(req.body);
  console.log("===错误中间件指向===");
  if (err) {
    console.log("===============错误==================");
    console.log("err=", JSON.stringify(err));
    console.log("=====================================");
  }
  if (err.name === 'UnauthorizedError') return res.onError('登录过期，身份认证失败!')
  // 数据验证失败
  if (err instanceof joi.ValidationError) {
    return res.send(err)
  }
  // 未知错误
  res.send(err)
})



// 调用 app.listen 方法，指定端口号并启动web服务器
app.listen(3000, function () {
  console.log('api server running at http://127.0.0.1:3000')
})
